// Copyright (c) Microsoft
// All rights reserved
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
// INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
// See the Apache Version 2.0 License for specific language governing permissions and limitations under the License.
/// <tags>P1</tags>
/// <summary>Test tile() const member function on const objects</summary>
// RUN: %amp_device -D__GPU__ %s -m32 -emit-llvm -c -S -O3 -o %t.ll && mkdir -p %t
// RUN: %llc -march=c -o %t/kernel_.cl < %t.ll
// RUN: cat %opencl_math_dir/opencl_math.cl %t/kernel_.cl > %t/kernel.cl
// RUN: pushd %t && objcopy -B i386:x86-64 -I binary -O elf64-x86-64 kernel.cl %t/kernel.o && popd
// RUN: %cxxamp %link %t/kernel.o %s -o %t.out && %t.out
#include "./../tile.h"

#define INVOKE_TEST_FUNC_ON_CPU_AND_GPU(_func, ...) [&]() { \
	/* Invoke on cpu */ \
	int cpu_result = _func(__VA_ARGS__); \
	/* Invoke on gpu */ \
	int gpu_result; \
	concurrency::array_view<int, 1> gpu_resultv(1, &gpu_result); \
    gpu_resultv.discard_data(); \
	concurrency::parallel_for_each(gpu_resultv.get_extent() \
		, [=](concurrency::index<1> idx) restrict(amp) { \
		gpu_resultv[idx] = _func(__VA_ARGS__); \
	}); \
	gpu_resultv.synchronize(); \
		return cpu_result & gpu_result; \
}()

template<typename _type>
bool test_tile() restrict(amp,cpu)
{
    // tile 1D 20 extent extent by 5
    {
        const int extsize = 256;
        const int tileby = 8;
        const int dim = 1;
        extent<dim> e1(extsize);
        const extent<dim> g1(e1);
    
        const tiled_extent<tileby> t1 = g1.tile<tileby>();
    }

    // tile 2D 512 extent extent by 16
    {
        const int extsize = 512;
        const int tileby = 16;
        const int dim = 2;
        extent<dim> e2(extsize, extsize);
        const extent<dim> g2(e2);
    
        const tiled_extent<tileby, tileby> t2 = g2.tile<tileby, tileby>();
    }

    // tile 3D 1024 extent extent by 16
    {
        const int extsize = 1024;
        const int tileby = 32;
        const int dim = 3;
        extent<dim> e3(extsize, extsize, extsize);
        const extent<dim> g3(e3);
    
        const tiled_extent<tileby, tileby, tileby> t3 = g3.tile<tileby, tileby, tileby>();
    }

    // No validation here - For any change in const member function compiler will complain
    return true;
}

int main() 
{
	//accelerator_view av = require_device().get_default_view();

	int result = 1;
	result &= INVOKE_TEST_FUNC_ON_CPU_AND_GPU([]() restrict(amp,cpu)->bool{return test_tile<extent<1>>();});
	return result;
}

